<?php

/**
 * Created by PhpStorm.
 * User: meiyun1
 * Date: 2017/2/24
 * Time: 下午1:22
 */

namespace App\Http\Controllers\App;

use App\App\Services\AlipayService;
use App\App\Services\CsvReaderService;
use App\App\Services\StorageService;
use App\App\Services\WechatService;
use App\Exceptions\ExceptionCode;
use App\Models\Activity\ActivityService;
use App\Models\ActivityInfo\ActivityInfoService;
use App\Models\ActivityPrize\ActivityPrizeService;
use App\Models\ActivityRecord\ActivityRecord;
use App\Models\ActivityRecord\ActivityRecordService;
use App\Models\Participant\ParticipantService;
use App\Models\Prize\PrizeService;
use App\Models\PrizeType\PrizeType;
use App\Models\Sponsor\SponsorService;
use App\Support\Helpers\UtilsHelper;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class Controller extends \App\Http\Controllers\Controller
{
    public $request;
    public $response;
    public $activityService;
    public $activityPrizeService;
    public $prizeService;
    public $activityInfoService;
    public $storageService;
    public $activityRecordService;
    public $wechatService;
    public $csvReaderService;
    public $alipayService;
    public $sponsorService;
    public $participantService;

    public function __construct(
        Request $request,
                                Response $response,
                                ActivityService $activityService,
                                ActivityPrizeService $activityPrizeService,
                                PrizeService $prizeService,
                                ActivityInfoService $activityInfoService,
                                StorageService $storageService,
                                ActivityRecordService $activityRecordService,
                                WechatService $wechatService,
                                CsvReaderService $csvReaderService,
                                AlipayService $alipayService,
                                SponsorService $sponsorService,
                                ParticipantService $participantService
    ) {
        $this->request = $request;
        $this->response = $response;
        $this->activityService = $activityService;
        $this->activityPrizeService = $activityPrizeService;
        $this->prizeService = $prizeService;
        $this->activityInfoService = $activityInfoService;
        $this->storageService = $storageService;
        $this->activityRecordService = $activityRecordService;
        $this->wechatService = $wechatService;
        $this->csvReaderService = $csvReaderService;
        $this->alipayService = $alipayService;
        $this->sponsorService = $sponsorService;
        $this->participantService = $participantService;
    }


    /**
     * @param $activity_id
     * @return mixed
     */
    protected function getActivityDetail($activity_id)
    {
        $redis = Redis::connection();
        $activity = unserialize($redis->hGet('activityDetail', $activity_id));
        if (empty($activity)) {
            $activity = $this->activityService->findOne($activity_id);
            if (empty($activity)) {
                abort(404);
            }
            $activity->model;
            $activity->template;
            $activity->prizes;
            $activity = $activity->toArray();
            $shares = json_decode($activity['shares'], true);
            $shares['icon'] = isset($shares['icon']) ? $this->storageService->tomedia($shares['icon']) : '';
            $shares['qrcode'] = isset($shares['qrcode']) ? $this->storageService->tomedia($shares['qrcode']) : '';
            $activity['shares'] = json_encode($shares);
            $redis->hSet('activityDetail', $activity_id, serialize($activity));
        }
        $activity['backgroundImg'] = $this->storageService->tomedia($activity['backgroundImg']);
        return $activity;
    }

    /**
     * @param $activity_id
     */
    protected function updateActivityViews($activity_id)
    {
        $hasView = $this->request->cookie('hasView:' . $activity_id);
        if (empty($hasView)) {
            $activity = $this->activityService->findOne($activity_id);
            $activity->clicks = ++$activity->clicks;
            $activity->save();
        }
    }

    protected function getActivityPrizes($activity_id)
    {
        $prizelist = $this->activityPrizeService->findList([['activity_id', $activity_id]]);
        $list = [];
        foreach ($prizelist as $row) {
            $item = [
                'name' => $row->prize->name,
                'id' => $row->prize->id,
                'type_name' => $row->prize->prizeType->name,
                'type_code' => $row->prize->prizeType->code,
                'exchange_method' => $row->prize->exchange_method,
                'exchange_address' => $row->prize->exchange_address,
                'stock_limit' => $row->stock_limit,
                'image' => $this->storageService->tomedia($row->prize->background_image),
                'surplus' => $row->surplus,
                'max_amount' => $row->max_amount,
                'winning_limit' => $row->winning_limit,
                'winning_probability' => $row->winning_probability
            ];
            if (empty($row->prize->expired_start) && empty($row->prize->expired_end)) {
                $item['isExpire'] = true;
            } else {
                if (strtotime($row->prize->expired_start) <= time() && strtotime($row->prize->expired_end) >= time()) {
                    $item['isExpire'] = true;
                } else {
                    $item['isExpire'] = false;
                }
            }

            $list[] = $item;
        }
        return $list;
    }

    protected function getLuckPrizeByActivity($activity_id, $openid)
    {
        $checkRes = $this->checkActivityDrawLimit($activity_id, $openid);
        if ($checkRes['code'] != 0) {
            return $checkRes;
        }
        $this->updateActivityJoins($activity_id);
        $prizeList = $this->getActivityPrizes($activity_id);
        $validPrizes = [];
        foreach ($prizeList as $row) {
            if ($row['surplus'] == 0 || !$row['isExpire']) {
                continue;
            }
            $validPrizes[] = $row;
        }
        unset($prizeList);
        $prizeListCollection = collect($validPrizes);
        $all_winning_probability = $prizeListCollection->sum('winning_probability');
        $validPrizes[] = [
            'id' => 0,
            'name' => '谢谢参与',
            'winning_probability' => 100 - $all_winning_probability
        ];

        $result = $this->get_rand($validPrizes, $activity_id, $openid);

        if (!empty($result['id'])) {
            if (in_array($result['type_code'], [PrizeType::WECHAT, PrizeType::ALIPAY])) {
                $fee = $this->get_randRedPack($result);
                if ($fee > $result['surplus']) {
                    $result = [
                        'id' => 0,
                        'name' => '谢谢参与',
                    ];
                } else {
                    $result['fee'] = $fee;
                }
            }
        }
        if (!empty($result['id'])) {
            if (!$this->checkPrizeDrawAllLimit($result, $activity_id) || !$this->checkPrizeDrawLimit($result, $activity_id, $openid)) {
                $result = [
                    'id' => 0,
                    'name' => '谢谢参与',
                ];
            }
        }
        $this->createActivityRecord($result, $activity_id, $openid);
        if (isset($result['winning_probability'])) {
            unset($result['winning_probability']);
        }
        if ($result['id'] !== 0) {
            $sponsor = $this->activityInfoService->randomSponsor($result['id']);
            if (!empty($sponsor)) {
                $sponsor['logo'] = $this->storageService->tomedia($sponsor['logo']);
            }
            $result['sponsor'] = $sponsor;

            $this->updateActivityWinnings($activity_id);
        }
        return [
            'code' => 0,
            'prize' => $result
        ];
    }

    protected function createActivityRecord($prize, $activity_id, $openid)
    {
        $record = [
            'activity_id' => $activity_id,
            'openid' => $openid,
            'number' => isset($prize['number']) ? $prize['number'] : 1
        ];
        if (!empty($prize['id'])) {
            $record['prize_id'] = $prize['id'];
            $activity_prize = $this->activityPrizeService->findList([['activity_id', $activity_id], ['prize_id', $prize['id']]])->first();
            $surplus = $activity_prize->surplus - 1;
            if (in_array($prize['type_code'], [PrizeType::WECHAT, PrizeType::ALIPAY])) {
                $record['amount'] = $prize['fee'];
                $surplus = $activity_prize->surplus - $prize['fee'];
            }
            if ($prize['type_code'] == PrizeType::COUPON) {
                $prizeInfo = $this->activityInfoService->destributeActivity($activity_id, $prize['id'], $this->activityRecordService, $this->storageService, $this->csvReaderService);
                $record['coupon'] = $prizeInfo['voucher_code'];
            }
            $activity_prize->surplus = $surplus;
            $activity_prize->save();
        }
        $this->activityRecordService->create($record);
    }

    private function get_rand($proArr, $activity_id, $openid)
    {
        $activity = $this->getActivityDetail($activity_id);
        $rule = json_decode($activity['rule'], true);
        if (isset($rule['spec']) && $rule['spec']['isopen'] == 1 && isset($rule['spec']['list'])) {
            foreach ($rule['spec']['list'] as $spec) {
                if (strtotime($spec['start']) <= time() && strtotime($spec['end']) >= time()) {
                    if (!$this->checkSpecPrizeDrawLimit($spec, $activity_id, $openid)) {
                        continue;
                    } else {
                        $prize_id = $spec['prize'];
                        break;
                    }
                } else {
                    continue;
                }
            }
        }
        if (isset($prize_id)) {
            $result = collect($proArr)->filter(function ($value) use ($prize_id) {
                if ((string)$value['id'] == $prize_id) {
                    return true;
                }
                return false;
            });
            return $result->first();
        }
        $proArr = UtilsHelper::sortByCol($proArr, 'winning_probability', SORT_ASC);

        $proSum = 100;
        foreach ($proArr as $proCur) {
            $randNum = $this->randomFloat(0, $proSum);
            if ($randNum <= $proCur['winning_probability']) {
                $result = $proCur;
                break;
            } else {
                $proSum -= $proCur['winning_probability'];
            }
        }
        unset($proArr);
        return $result;
    }

    private function get_randRedPack($prize)
    {
        $fee = rand(100, $prize['max_amount'] * 100);
        return sprintf('%.2f', $fee / 100);
    }

    private function randomFloat($min = 0, $max = 10)
    {
        $num = $min + mt_rand() / mt_getrandmax() * ($max - $min);
        return sprintf("%.2f", $num);
    }

    private function checkActivityDrawLimit($activity_id, $openid)
    {
        $activity = $this->getActivityDetail($activity_id);
        $limit = json_decode($activity['limit'], true);
        if ($limit['type'] == 'all') {
            $user_limit = $this->activityRecordService->count([['activity_id', $activity_id], ['openid', $openid]]);
            if ($user_limit >= $limit['num']) {
                return [
                    'code' => ExceptionCode::GENERAL,
                    'message' => '你参与的抽奖次数已达上限'
                ];
            }
        } else {
            $user_limit = $this->activityRecordService->count([['activity_id', $activity_id], ['openid', $openid], ['created_at', '>=', date("Y-m-d")], ['created_at', '<', date("Y-m-d", strtotime("+1 day"))]]);
            if ($user_limit >= $limit['num']) {
                return [
                    'code' => ExceptionCode::GENERAL,
                    'message' => '你今天抽奖的次数已达上限'
                ];
            }
        }
        return [
            'code' => 0
        ];
        ;
    }

    private function checkPrizeDrawLimit($prize, $activity_id, $openid)
    {
        $user_prize_limit = $this->activityRecordService->count([['activity_id', $activity_id], ['prize_id', $prize['id']], ['openid', $openid]]);
        if ($user_prize_limit >= $prize['winning_limit'] && $prize['winning_limit'] != 0) {
            return false;
        }
        return true;
    }

    private function checkPrizeDrawAllLimit($prize, $activity_id)
    {
        if (in_array($prize['type_code'], [PrizeType::WECHAT, PrizeType::ALIPAY])) {
            return true;
        }
        $prize_limit = $this->activityRecordService->count([['activity_id', $activity_id], ['prize_id', $prize['id']]]);
        if ($prize_limit > $prize['stock_limit']) {
            return false;
        }
        return true;
    }

    private function checkSpecPrizeDrawLimit($spec, $activity_id, $openid)
    {
        $user_prize_limit = $this->activityRecordService->count([
            ['activity_id', $activity_id],
            ['prize_id', $spec['prize']],
            ['openid', $openid],
            ['created_at', '>=', $spec['start']],
            ['created_at', '<=', $spec['end']]
        ]);

        if ($user_prize_limit >= $spec['times']) {
            return false;
        }

        return true;
    }

    private function updateActivityJoins($activity_id)
    {
        $activity = $this->activityService->findOne($activity_id);
        $activity->joins = ++$activity->joins;
        $activity->save();
    }

    private function updateActivityWinnings($activity_id)
    {
        $activity = $this->activityService->findOne($activity_id);
        $activity->winnings = ++$activity->winnings;
        $activity->save();
    }


    protected function receivePrize($activity_id, $prize_id, $userInfo)
    {
        $activity = $this->getActivityDetail($activity_id);
        $result = [
            'code' => 0
        ];
        $prize = $this->prizeService->getPrizeById($prize_id);
        $prizeInfo = [
            'name' => $prize['name'],
            'image' => $this->storageService->tomedia($prize['background_image']),
            'type_code' => $prize['type_code']
        ];
        $activityRecord = $this->activityRecordService->findOneByConditions([['activity_id', $activity_id], ['prize_id', $prize_id], ['openid', $userInfo['participantid']]], ['created_at', 'desc']);
        if ($activityRecord->is_exchange == ActivityRecord::EXCHANGED) {
            return [
                'code' => ExceptionCode::GENERAL,
                'message' => '你已经兑换领取了该奖品'
            ];
        }
        switch ($prize['type_code']) {
            case PrizeType::WECHAT:
                $prizeInfo['name'] = '现金红包';
                $sponsor = $this->activityInfoService->randomSponsor($prize_id);
                $redpack_act = [
                    'provider' => !empty($sponsor) ? $sponsor['name'] : '成都华栖云',
                    'wish' => '感谢您参加' . $activity['name'],
                    'name' => $activity['name']
                ];
                $redpack_act['remark'] = '感谢' . $redpack_act['provider'] . '赞助本次活动';
                $resInfo = $this->wechatService->send($redpack_act, [
                    'redpack' => $activityRecord->amount,
                    'openid' => $userInfo['openid']
                ]);
                Log::info($resInfo);
                if (UtilsHelper::is_error($resInfo)) {
                    $result = [
                        'code' => ExceptionCode::GENERAL,
                        'message' => '领取红包失败'
                    ];
                } else {
                    $result = [
                        'message' => '领取红包成功',
                        'code' => 0
                    ];
                    $activityRecord->is_exchange = ActivityRecord::EXCHANGED;
                    $activityRecord->save();
                }
                break;
            case PrizeType::ALIPAY:
                $prizeInfo['name'] = '现金红包';
                $activityRecord->alipay = $userInfo['alipay'];
                $activityRecord->save();
                $result_data = $this->alipayService->transferAccounts($activityRecord->id);
                if ($result_data['res']) {
                    $result['message'] = '领取红包成功';
                } else {
                    $result = [
                        'code' => ExceptionCode::GENERAL,
                        'message' => $result_data['msg']
                    ];
                }
                break;
            case PrizeType::ENTITY:
                if (empty($userInfo['name']) || empty($userInfo['mobile'])) {
                    $result = [
                        'code' => ExceptionCode::GENERAL,
                        'message' => '联系方式请填写完整'
                    ];
                } else {
                    $activityRecord->name = $userInfo['name'];
                    $activityRecord->mobile = $userInfo['mobile'];
                    $activityRecord->address = $userInfo['address'];
                    $activityRecord->save();
                }
                break;
            case PrizeType::COUPON:
                $prizeInfo['coupon'] = $activityRecord->coupon;
                break;
        }
        if ($result['code'] == 0) {
            $result['prize'] = $prizeInfo;
        }
        return $result;
    }

    protected function getParticipantByID($id)
    {
        if (empty($id)) {
            return null;
        }
        return $this->participantService->getParticipantbyId($id);
    }

    protected function createParticipant($openID, $source)
    {
        if (empty($openID) || empty($source)) {
            return null;
        }
        return $this->participantService->createParticipant($openID, $source);
    }
}
